﻿using System.Collections.Generic;
using Internal.KuiHuaBaoDian.Services.Battle.Behaviour;
using Internal.KuiHuaBaoDian.Services.Battle.Entity;
using KuiHuaBaoDian.Services.Battle.Behaviour;
using KuiHuaBaoDian.Services.Battle.Entity;
using KuiHuaBaoDian.Services.Lockstep;
using UnityEngine;

namespace KuiHuaBaoDian.Services.Battle.Entity {

    /// <summary>
    /// 战斗实体
    /// </summary>
    public interface IBattleEntity : ILockstepEntity, IEntity {
    }

    public abstract class KHBD_BattleEntity : KHBD_Entity, IBattleEntity, IBattleEntityInternal, IBattleEntityStateSpeedGetter {

        private event IBattleEntityInternal.EntityDelegate Attached;
        event IBattleEntityInternal.EntityDelegate IBattleEntityInternal.Attached {
            add => Attached += value;
            remove => Attached -= value;
        }

        private event IBattleEntityInternal.EntityDelegate Detached;
        event IBattleEntityInternal.EntityDelegate IBattleEntityInternal.Detached {
            add => Detached += value;
            remove => Detached -= value;
        }

        public BattleEntityHandle Handle { get; private set; }

        protected GameObject Container { get; private set; }

        protected List<IBattleBehaviourInfo> BehaviourInfoList { get; private set; } = new();

        protected IBattleEntityAssetVehicle StateVehicle { get; private set; }

        protected IBattleEntityAssetVehicle SFXVehicle { get; private set; }

        float IBattleEntityStateSpeedGetter.GetValue(BattleEntityState state) => GetStateSpeed(state);
        protected abstract float GetStateSpeed(BattleEntityState state);

        protected abstract void DoLogicFrame(int frameIndex);
        void ILockstepEntity.DoLogicFrame(int frameIndex) {
            DoLogicFrame(frameIndex);
        }

        protected abstract void EndUpdate(float timeScale);

        protected abstract void DoExecute(IBattleBehaviourInfo behaviourInfo);

        protected abstract void DoUpdate();

        void ILockstepEntity.DoUpdate(int frameIndex, int syncedFrameCount, float deltaTime, float timeScale) {
            if (IsDisposed) {
                return;
            }
            for (var i = 0; i < BehaviourInfoList.Count; ++i) {
                var behaviourInfo = BehaviourInfoList[i];
                if ((behaviourInfo as IBattleBehaviourInfoInternal).FrameIndex > LockstepService.Instance.AccumulatedFrame) {
                    break;
                }
                DoExecute(behaviourInfo);
                BehaviourInfoList.RemoveAt(i--);
            }
            DoUpdate();
            EndUpdate(timeScale);
        }

        void ILockstepEntity.OnAttached(int frameIndex) {
            Attached?.Invoke();
        }

        void ILockstepEntity.OnDetached() => Detached?.Invoke();

        void IBattleEntityInternal.Initialize(BattleEntityHandle handle, GameObject container, IBattleEntityAssetVehicle stateVehicle, IBattleEntityAssetVehicle sfxVehicle) {
            Handle = handle;
            Container = container;
            StateVehicle = stateVehicle;
            SFXVehicle = sfxVehicle;
        }

        protected override void Dispose() {
            Attached = null;
            Detached = null;
            Container = null;
            StateVehicle = null;
            SFXVehicle = null;
            BehaviourInfoList = null;
        }
    }
}

namespace Internal.KuiHuaBaoDian.Services.Battle.Entity {

    public interface IBattleEntityInternal {

        public delegate void EntityDelegate();

        event EntityDelegate Attached;

        event EntityDelegate Detached;

        void Initialize(BattleEntityHandle handle, GameObject container, IBattleEntityAssetVehicle stateVehicle, IBattleEntityAssetVehicle sfxVehicle);
    }
}